All files / src/app/recipes/[id] RecipeDetailClient.tsx

0% Statements 0/9
0% Branches 0/10
0% Functions 0/1
0% Lines 0/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                                                                                                                                                                                                                     
'use client';
 
import {
  Center,
  Container,
  Grid,
  Loader,
  Paper,
  Stack,
  Title,
} from '@mantine/core';
import type { Route } from 'next';
import { useTranslations } from 'next-intl';
import { BackTo } from '@/components/buttons/BackTo';
import RecipeRating from '@/components/Recipe/Rating';
import { RecipeHero } from './components/RecipeHero';
import { RecipeIngredients } from './components/RecipeIngredients';
import { RecipeNotFound } from './components/RecipeNotFound';
import { RecipeSteps } from './components/RecipeSteps';
import { RecipeVideo } from './components/RecipeVideo';
import { useRecipeDetail } from './hooks/useRecipeDetail';
import type { RecipeDetailClientProps } from './types';
 
const RecipeDetailClient = ({
  recipeId,
}: Readonly<RecipeDetailClientProps>) => {
  const translate = useTranslations('recipeDetail');
 
  const {
    recipe,
    loading,
    error,
    servingMultiplier,
    adjustedServings,
    checkedIngredients,
    toggleIngredient,
    incrementServings,
    decrementServings,
    youtubeId,
    isOwner,
    sortedSteps,
  } = useRecipeDetail(recipeId);
 
  if (loading) {
    return (
      <Center h="60vh">
        <Loader size="lg" type="dots" />
      </Center>
    );
  }
 
  if (error || !recipe) {
    return <RecipeNotFound errorMessage={error?.message} />;
  }
 
  return (
    <Container size="xl" py="xl">
      <Stack gap="xl">
        <BackTo href={'/recipes' as Route} text={translate('backToRecipes')} />
 
        <RecipeHero recipe={recipe} isOwner={isOwner} />
 
        <Grid gap="xl">
          {/* Left column – Steps */}
          <Grid.Col span={{ base: 12, md: 7 }}>
            <Stack gap="xl">
              <RecipeSteps steps={sortedSteps} />
 
              {youtubeId && (
                <RecipeVideo youtubeId={youtubeId} title={recipe.title} />
              )}
 
              {/* Rating */}
              <Paper p="lg" radius="md" withBorder>
                <Title order={3} size="h4" mb="sm">
                  {translate('rateThisRecipe')}
                </Title>
                <RecipeRating
                  recipeId={recipe.id}
                  userRating={recipe.userRating ?? undefined}
                  averageRating={recipe.averageRating}
                  ratingsCount={recipe.ratingsCount}
                />
              </Paper>
            </Stack>
          </Grid.Col>
 
          {/* Right column – Ingredients (sticky) */}
          <Grid.Col span={{ base: 12, md: 5 }}>
            <RecipeIngredients
              ingredients={recipe.ingredients}
              servingMultiplier={servingMultiplier}
              adjustedServings={adjustedServings}
              checkedIngredients={checkedIngredients}
              onToggleIngredient={toggleIngredient}
              onIncrementServings={incrementServings}
              onDecrementServings={decrementServings}
            />
          </Grid.Col>
        </Grid>
      </Stack>
    </Container>
  );
};
 
export default RecipeDetailClient;